/**
 *  world model
 *  Author: mrsang(L), Geoffrey (L)
 *  Description: Examiner l'influence de la retroaction negative sur
 *	le commportement individuel et de l'exploitation collective des 
 *	fourmis 
 */
model AntWithDensity

global {
	//la taille de l'environnement en carre
	int world_size <- 70 min:50 max:100 parameter:"Env. size" category:"Environnement";
	//Le nombre de fournies chez le nid
	int population_size<-20 min:1 max:2000 parameter:"Size of Population" category: 'Environnement';
	//La proportion de la perte du signal de pheromone 
	float phe_decay_rate<-0.1 min:0.1 max:1.0 parameter:"Pheromone missing rate" category: 'Environnement';
	float diffusion_rate <- 0.5 min: 0.0 max: 1.0 parameter:"Diffusion rate" category: 'Environnement';
	//Le nombre maximal des fourmis chez une source de nourriture
	int max_source_slots <- 2 min:1 max:100 parameter:"Max number of ants per feeder" category: 'Feeder';
	int loading_time<-20 min:10 max:100 parameter:"Loading time" category: 'Ant';
	//Le delai pour qu'une nouvelle source apparait 
	int source_delay <-300 min:0 max:1000 parameter:"Delay for creating new feeder" category: 'Feeder';
	int par_no_sources<-4 min:1 max:10 parameter:"No. of feeder" category: 'Feeder';
	int max_source_food<-15 min:10 max:20 parameter:"Quantity of feeder" category: 'Feeder';//*5
	int food_per_place<-20 min:1 max:100  parameter:"Quantity of food per place" category: 'Feeder';
	int food_decay_rate<-1 min:1 max:10 parameter:"Rate of foods decay" category:'0.2 Feeder';
	int food_decay_interval<-25 min:1 max:300 parameter:"Food decay interval" category:'0.2 Feeder'; //in cicle
	int food_gathered <- 0 ;
	int time_delay<-source_delay	;
	int no_sources<-par_no_sources;
	int food_missing<-0;
	
	const ant_empty type:string<-"../images/ant_nomal.png";
	const ant_full type:string<-"../images/ant_with_food.png";
	//const ant_feeding type:string<-"../images/ant_feeding.png";
	const ant_waiting type:string<-"../images/ant_waiting.png";
	const center type:point <- {world_size/2,world_size/2};
		
	init{
		//write message:population_size;
		create ant number:population_size{
			set location<-any_location_in (ant_world(center)); 
		}
		if(no_sources>0)
		{
			create food_source number:1;
			set no_sources<- no_sources-1;
		}
	}
	reflex stop_simulation when:length(list(food_source) where (each.food_quantity>0))=0 and no_sources=0 {
		do halt ;
	} 
	reflex init_source when:no_sources>0 and time>time_delay
	{
		create food_source number:1;
		set no_sources<- no_sources-1;
		set time_delay<-time+source_delay;
	}
}

environment width:world_size height:world_size {
	grid ant_world width: world_size height: world_size neighbours: 8 {
		const neighbours <- self neighbours_at 1 type: list of: ant_world ;
		food_source source<-nil;
		bool is_at_home  <- (self distance_to center) < 3;
		bool is_at_source; 
		rgb color <-is_at_home ? rgb("gray"):(is_at_source?rgb("blue"):(trait>0?rgb("#beffa0"):rgb("white"))) update:is_at_home ? rgb("gray"):(is_at_source?rgb("blue"):(trait>0?rgb("#beffa0"):rgb("white")));
		int food <- is_at_source ? food_per_place : 0;
		const nest type: int <-350 - int(self distance_to center) ;
		food_piece piece<-nil;
		reflex change_stat when:(is_at_source and food=0){
			set is_at_source<-false;
			set food<-0;
			set source<-nil;
			if(piece != nil)
			{
				ask piece{
					do die;
				}
			}
			set piece<-nil;
		}
	}
		
}

entities {
	species ant skills:[moving] control:fsm{
		rgb color<-rgb("orange");
		ant_world place update:ant_world(location);
		int delay<-0;
		bool has_food<-false;
		bool loading<-false;
		bool waiting<-false;
		bool followingTrait<-false update:place.trait>0.05;
		signal trait value: has_food ? 240.0 : 0.0 decay: phe_decay_rate proportion: diffusion_rate environment: ant_world ;
		string ant_shape<-waiting ? ant_waiting:(has_food?ant_full:ant_empty) update:waiting ? ant_waiting:(has_food?ant_full:ant_empty);
		action pick {
			set waiting<-false;
			set loading<-true;
			set delay <- time+loading_time;
			set color<-rgb("red");
			set place.food<-place.food-1;
			set place.source.food_quantity <- place.source.food_quantity-1;
			set food_gathered <- food_gathered + 1 ;
			//do write message: place.source.food_quantity;
		}
		action drop {
			
			set has_food <- false ;

			set heading <- heading - 180 ;
			set color<-rgb("orange");
		}
		state wandering initial: true {
			
			do wander amplitude:90 speed:1.0;
			set waiting<-false;
			transition to: loadingFood when:place.is_at_source and (place.food>0) and place.source.acessable{	
					//write "slot"+ place.source.slots;
					do pick;
			}
			transition to:waiting when:place.is_at_source and place.food>0 and place.source.acessable = false;
			
			transition to: followingRoad when: place.trait > 0.05;
		}
		state waiting{
			
			set waiting<-true;
			transition to: loadingFood when:place.is_at_source and place.food>0 and place.source.acessable{	
					do pick;
			}
			transition to: wandering when: place.food=0 ;
		}
		state loadingFood
		{
			
			transition to:carryingFood when:time>delay{
				set delay<-0;
				set has_food<-true;
				set loading<-false;
			}
		}
		
		state followingRoad{
			
			let candidats type:list<-list(place.neighbours);
			let candidat type:ant_world<-nil;
			if(candidats count (each.food)>0)
			{
				set candidat <-candidats first_with(each.food >0);
			}
			else
			{
				//let min_nest  <-  (candidats min_of (each.nest)) ;
				set candidats <- candidats sort ((each.nest <= self.place.nest and each.location != location) ? each.trait : 0.0) ;
				set candidat<-last(candidats);
			}
			
			set location<-candidat.location;
			transition to: loadingFood when:place.is_at_source and (place.food>0 ) and place.source.acessable{					//write message:"no slots"+source.slots;
					//write "slot"+ place.source.slots;
					do pick;
			}
			transition to:waiting when:place.is_at_source and place.food>0 and place.source.acessable = false;
			transition to:wandering when:place.trait<0.05;
		}
		state carryingFood {
			
			do goto target:center;
			transition to:wandering when:place.is_at_home and has_food{
				do drop;
			}
		}
		aspect base{
			draw shape:circle color:color;
		}
		aspect icon {
			draw image : ant_shape at : my location size : 3 rotate : my heading + 1;
		}
	}
	species food_source skills:[situated] {
		int food_quantity<-max_source_food*food_per_place;
		geometry sil<-nil;
		bool acessable<-sil != nil and length(list(ant inside(sil) where (each.loading = true)))<max_source_slots update:length(list(ant inside(sil) where (each.loading = true)))<max_source_slots;
		bool found<-sil != nil and length(list(ant inside(sil) where (each.loading = true or each.waiting=true)))>0 update:length(list(ant inside(sil) where (each.loading = true or each.waiting=true)))>0;
		init{
			let nb type:int<-food_quantity/food_per_place;
			let case type:ant_world<- one_of(list(ant_world) where(each.is_at_home=false and each.is_at_source=false));
			set location<-case.location;
			//do write message:"create source "+food_quantity + "->"+nb;
			set sil<-case;
			loop while: nb>0 {
				ask case{
					set is_at_source<-true;
					set source<-myself;
					set food<-food_per_place;
					create food_piece number:1{
						set location<-myself.location;
						set myself.piece<-self;
					}
				}
				set nb<-nb-1;
				set case<-one_of(case.neighbours where(each.is_at_source=false and each.is_at_home=false));
				set sil<-sil+case;
			}
		}
		reflex food_decay when: time != 0 and time mod  food_decay_interval = 0 
		{
			if(sil != nil)
			{
				let place type:ant_world <- last(list(ant_world inside(sil) where(each.is_at_source and each.food>0)) sort_by(each.food));
				if(place != nil)
				{
					ask place{
						//write message:"Food decay";
						set food_missing<-food_missing + (food>food_decay_rate?food_decay_rate:food);
						set source.food_quantity <- source.food_quantity- (food>food_decay_rate?food_decay_rate:food);
						set food<-food - (food>food_decay_rate?food_decay_rate:food);			
					}
				} 
			}
			
		}
	} 
	//decoration only
	species food_piece skills:[situated]{
		const img type:string<-"../images/food.png";
		const angle type:int <-rnd(360);
		aspect icon {
			draw image : img at :location size : 3 rotate:angle;
		}
	}
}

experiment "Stable Environnement" type: gui {
	parameter 'Time delay:' var: source_delay init:0 category: 'Environnement' ;
	output{
		display Ants refresh_every: 1 {
			species food_source aspect:base;
			grid ant_world lines:rgb ( 'lightGray' );
			species food_piece aspect: icon;
			species ant aspect: icon;
		}
		display "Forage status" refresh_every: 5 {
			chart name: 'Ants status' type: series background: rgb('white') size: {0.9, 0.4} position: {0.05, 0.05} {
				data 'Fourmis forageant' value: length(list(ant) where (each.has_food = false and each.waiting = false and each.loading = false and each.followingTrait=false)) style: step color: rgb('red') ;
				data 'Fourmis attendant' value:length(list(ant) where ((each as ant).waiting = true )) style:step color:rgb('blue');
				data 'Fourmis suivant la trace' value: length(list(ant) where (each.has_food = false and each.waiting = false and each.loading = false and each.followingTrait=true)) style: step color: rgb('green') ;
				data 'Fourmis chargeant' value:length(list(ant) where ((each as ant).loading = true)) style:step color:rgb('orange');
			}
			chart name: 'Source' type: series background: rgb('white') size: {0.9, 0.4} position: {0.05, 0.55} {
				data 'Nourrisseurs decouverts' value:length(list(food_source) where (each.found=true)) style:step color:rgb("blue");
			}
		}
		display "Foods collected status" refresh_every: 5 {
			chart name: 'Foods collected status' type: pie style: exploded background: rgb('white') size: {0.9, 0.9} position: {0.05, 0.05} {
				data 'Food gathered' value:food_gathered color: rgb('red') ;
				data 'Food missing' value:food_missing color: rgb('orange') ;
				data 'Food available' value:sum(list(food_source) collect (each.food_quantity)) color:rgb('blue');
			}
		}
	}
}
experiment "Changing Environnement" type: gui {
	parameter 'Time delay:' var: source_delay init:500 category: 'Environnement' ;
	output{
		display Ants refresh_every: 1 {
			species food_source aspect:base;
			grid ant_world lines:rgb ( 'lightGray' );
			species food_piece aspect: icon;
			species ant aspect: icon;
		}
		display "Forage status" refresh_every: 5 {
			chart name: 'Ants status' type: series background: rgb('white') size: {0.9, 0.4} position: {0.05, 0.05} {
				data 'Fourmis forageant' value: length(list(ant) where (each.has_food = false and each.waiting = false and each.loading = false and each.followingTrait=false)) style: step color: rgb('red') ;
				data 'Fourmis attendant' value:length(list(ant) where ((each as ant).waiting = true )) style:step color:rgb('blue');
				data 'Fourmis suivant la trace' value: length(list(ant) where (each.has_food = false and each.waiting = false and each.loading = false and each.followingTrait=true)) style: step color: rgb('green') ;
				data 'Fourmis chargeant' value:length(list(ant) where ((each as ant).loading = true)) style:step color:rgb('orange');
			}
			chart name: 'Source' type: series background: rgb('white') size: {0.9, 0.4} position: {0.05, 0.55} {
				data 'Nourrisseurs decouverts' value:length(list(food_source) where (each.found=true)) style:step color:rgb("blue");
			}
		}
		display "Foods collected status" refresh_every: 5 {
			chart name: 'Foods collected status' type: pie style: exploded background: rgb('white') size: {0.9, 0.9} position: {0.05, 0.05} {
				data 'Food gathered' value:food_gathered color: rgb('red') ;
				data 'Food missing' value:food_missing color: rgb('orange') ;
				data 'Food available' value:sum(list(food_source) collect (each.food_quantity)) color:rgb('blue');
			}
		}
	}
}
//batch mode for now
experiment "Batch" type: batch repeat:2 keep_seed:true until:length(list(food_source) where (each.food_quantity>0))=0 and no_sources = 0{
	parameter 'Time delay of new feeder:' var: source_delay<-300;
	parameter 'Size of Population' var:population_size<-50 min:50 max:500 step:50;
	parameter 'Size of the word' var:world_size<-100 min:100 max:1000 step:100;
	parameter 'Number of feeder' var:par_no_sources<-4;
	parameter "Number of food's places per feeder" var: max_source_food<-15;//*5
	parameter "Quantity of foods per place" var: food_per_place<-20;
	parameter "Rate of foods decay" var: food_decay_rate<-1;
	parameter "Foods decay interval" var: food_decay_interval<-25;
	parameter "Maximum number of ants per feeder" var:max_source_slots<-10;
	method exhaustive maximize:(food_gathered/food_missing);
	//method exhaustive minimize:  population_size;
}

